#include "protocol.h"
#include "fcntl.h"

Protocol::Protocol(){}

Protocol::~Protocol(){}

bool Protocol::Connect(char* ip, int port)
{
   #ifdef WII
     u32 status = net_init();
     #ifdef DEBUG_PROTOCOL
     printf("Net_init returned (%d)\n",status);
     #endif
     if(status != 0){
        #ifdef DEBUG_PROTOCOL
        printf("Net_init failed.\n");
        #endif        return false;
     }
   #endif

   /*Create TCP Socket*/
   #ifdef WII
   if((m_sock = net_socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
   #else
   if((m_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Failed to create socket\n");
      #endif
      return false;
   }

   //make non blocking
   //fcntl(m_sock, F_SETFL, O_NONBLOCK);

   #ifdef DEBUG_PROTOCOL
   printf("Creating sockaddr...\n");
   #endif

   /*Construct server sockaddr_in struct*/
   memset(&m_server, 0, sizeof(m_server));
   m_server.sin_family = AF_INET;
   m_server.sin_addr.s_addr = inet_addr(ip);
   m_server.sin_port = htons(port);
     
   #ifdef DEBUG_PROTOCOL
   printf("Connecting...\n");
   #endif

   /*Establish Connection...*/
   #ifdef WII
   if(net_connect(m_sock, (struct sockaddr *) &m_server, sizeof(m_server)) == SOCKET_ERROR) {
   #else
   if(connect(m_sock, (struct sockaddr *) &m_server, sizeof(m_server)) < 0) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Failed to connect with server\n");
      #endif
      return false;
   }

   #ifdef DEBUG_PROTOCOL
   printf("Connected.\n");
   #endif

   return true;
}

void Protocol::Disconnect()
{
   close(m_sock);
}

bool Protocol::Update_Name(char* name)
{
   /*Update name*/
   bzero(m_message,256);
   sprintf(m_message, "%s%s%s%s%s\n", UPDATE,SPLIT,UPDATE_NAME,SPLIT,name);
   m_msglen = strlen(m_message);
   #ifdef LINUX
   if(send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #elif WII
   if(net_send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Mismatch in number of sent bytes\n");
      #endif
      return false;
   }
 
   return true;
}

bool Protocol::Send_Message(const char* msg, char* name)
{
   /*Update name*/
   bzero(m_message,256);
   sprintf(m_message, "%s%s%s%s%s\n", SEND_MSG,SPLIT,name,SPLIT,msg);
   m_msglen = strlen(m_message);
   #ifdef LINUX
   if(send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #elif WII
   if(net_send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Mismatch in number of sent bytes\n");
      #endif
      return false;
   }
 
   return true;
}

bool Protocol::Update_Pos(int x, int y, int z)
{
   /*Update pos*/
   bzero(m_message,256);
   sprintf(m_message, "%s%s%s%s%i,%i,%i\n", UPDATE,SPLIT,UPDATE_POS,SPLIT,x,y,z);
   m_msglen = strlen(m_message);
   #ifdef LINUX
   if(send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #elif WII
   if(net_send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Mismatch in number of sent bytes\n");
      #endif
      return false;
   }
 
   return true;
}

bool Protocol::Get_Uid()
{
   int bytes = 0;
   bzero(m_message,256);
   bzero(m_buffer,256);
   /*Request Mails*/
   sprintf(m_message, "%s\n", GET_UID);
   m_msglen = strlen(m_message);
   #ifdef LINUX
   if(send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #elif WII
   if(net_send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Mismatch in number of sent bytes\n");
      #endif
      return false;
   }

   return true;
}

bool Protocol::Rqst_Mail()
{
   int bytes = 0;
   bzero(m_message,256);
   bzero(m_buffer,256);
   /*Request Mails*/
   sprintf(m_message, "%s\n", REQUEST_MAIL);
   m_msglen = strlen(m_message);
   #ifdef LINUX
   if(send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #elif WII
   if(net_send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Mismatch in number of sent bytes\n");
      #endif
      return false;
   }

   return true;
}

bool Protocol::Rqst_User_List()
{
   int bytes = 0;
   bzero(m_message,256);
   bzero(m_buffer,256);

   /*Request Mails*/
   sprintf(m_message, "%s\n", REQUEST_USER_LIST);
   m_msglen = strlen(m_message);
   #ifdef LINUX
   if(send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #elif WII
   if(net_send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Mismatch in number of sent bytes\n");
      #endif
      return false;
   }

   return true;
}

bool Protocol::Send_Quit()
{
   /*Update name*/
   bzero(m_message,256);
   sprintf(m_message, "%s\n",QUIT);
   m_msglen = strlen(m_message);
   #ifdef LINUX
   if(send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #elif WII
   if(net_send(m_sock, m_message, m_msglen, 0) != m_msglen) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Mismatch in number of sent bytes\n");
      #endif
      return false;
   }
 
   return true;
}

MessageType::Type Protocol::Rcv_Handler()
{
   int bytes = 0;
   std::string tBuffer = "";

   fd_set fds;
   int n;
   struct timeval tv;

   FD_ZERO(&fds);
   FD_SET(m_sock, &fds);

   tv.tv_sec = 0;
   tv.tv_usec = 100;
   
   n = net_select(m_sock+1, &fds, NULL, NULL, &tv);

   if(n == 0) return MessageType::NONE; //timeout
   if(n == -1) return MessageType::NONE; //ERROR

   /*Update name*/
   bzero(m_buffer,256);

   /*Rcv Mail*/
   #ifdef LINUX
   if((bytes = recv(m_sock, m_buffer, BUFFER_LEN-1,0)) < 0) {
   #elif WII
   if((bytes = net_recv(m_sock, m_buffer, BUFFER_LEN-1,0)) < 0) {
   #endif
      #ifdef DEBUG_PROTOCOL
      printf("Failed to rcv bytes from server.\n");
      #endif
      return MessageType::NONE;
   }

   tBuffer = m_buffer;
   int lBrack = 0;
   int rBrack = 0;

   tBuffer = tBuffer.erase(tBuffer.find_last_not_of(" ") + 1); //trim space to right
   tBuffer = tBuffer.erase(0,tBuffer.find_first_not_of(" ")); //trim space to left

   lBrack = tBuffer.find("~$",lBrack);
   rBrack = tBuffer.find("$~",rBrack);

   if(lBrack != -1 && rBrack != -1){
      const char* str = (tBuffer.substr(lBrack+2,rBrack-lBrack-2)).c_str();
      if(strcmp(str,GET_UID)==0) return MessageType::UID_RESPONSE;
      else if(strcmp(str,REQUEST_MAIL)==0)return MessageType::MAIL_RESPONSE;
      else if(strcmp(str,REQUEST_USER_LIST)==0) return MessageType::USER_LIST_RESPONSE;
      else if(strcmp(str,REQUEST_ALL_DATA)==0) return MessageType::ALL_DATA_RESPONSE;
   }

   return MessageType::NONE;

   
}

void Protocol::Clear_Rcv_Buffer()
{
   bzero(m_buffer,256);
}

int Protocol::ParseUid(std::string buff)
{
   bool found = false;
   int lBrack = 0;
   int rBrack = 0;

   lBrack = buff.find("UID[",lBrack);
   rBrack = buff.find(']',rBrack);

    buff = buff.erase(buff.find_last_not_of("\n") + 1); //trim space to right

   if(lBrack != -1 && rBrack != -1){
      const char* str = (buff.substr(lBrack+4,rBrack-lBrack-2)).c_str();
      //printf("uidstr: (%s)",str);
      return atoi(str);
   }
   else
   {
      #ifdef DEBUG_PROTOCOL
      printf("Failed to get UID Buffer:(%s,%d,%d)\n",buff.c_str(),lBrack,rBrack);
      #endif
   }

   return -1;
}

char* Protocol::ParseName(std::string buff)
{
   int lBrack = 0;
   int rBrack = 0;

   rBrack=rBrack+1;
   lBrack = buff.find("NAME[",rBrack);
   rBrack = buff.find(']',rBrack);

   buff = buff.erase(buff.find_last_not_of("\n") + 1); //trim space to right

   if(lBrack != -1 && rBrack != -1){
      const char* str = (buff.substr(lBrack+1,rBrack-lBrack-1)).c_str();
      return (char*)str;
   }
   else
   {
      #ifdef DEBUG_PROTOCOL
      printf("Failed to get Name Buffer:(%s,%d,%d)\n",buff.c_str(),lBrack,rBrack);
      #endif
   }

   return NULL;
}

std::string Protocol::ParseUsers(std::string msg)
{
   bool found = false;
   int lBrack = 0;
   int rBrack = 0;
   int offset = 0;
   std::string ret = "";
   char tstr[200];
   do{
      lBrack = msg.find('[',offset);
      rBrack = msg.find(']',lBrack);

      msg = msg.erase(msg.find_last_not_of("\n") + 1); //trim space to right
      if(lBrack != -1 && rBrack != -1){
	 const char* str = (msg.substr(lBrack+1,rBrack-lBrack-1)).c_str();
         if(str != NULL && str != "" && str != " ")
         {
            sprintf(tstr,"%s\n",str);
            ret.append(tstr);
         }
      }

      offset = rBrack+1;
      //lbrack = offset;
   }while(lBrack != -1 && rBrack != -1);
   //printf("Parsed: %s\n",ret.c_str());
   return ret;
}

std::string Protocol::ParseMessages(std::string msg)
{
   bool found = false;
   int lBrack = 0;
   int rBrack = 0;
   int offset = 0;
   char tstr[500];
   std::string ret = "";
   //printf("PreMail:(%s)\n",msg.c_str());
   do{
      lBrack = msg.find('[',offset);
      rBrack = msg.find(']',lBrack);

      msg = msg.erase(msg.find_last_not_of("\n") + 1); //trim space to right
      if(lBrack != -1 && rBrack != -1){
	 const char* str = (msg.substr(lBrack+1,rBrack-lBrack-1)).c_str();
         //printf("Mail:(%s)\n",str);
         if(str != NULL && str != "" && str != " ")
         {
            sprintf(tstr,"%s\n",str);
            ret.append(tstr);
         }
      }

      offset = rBrack;
   }while(lBrack != -1 && rBrack != -1);
   //printf("Parsed: %s\n",ret.c_str());
   return ret;
}
